package edu.mtu.citizenscience.cs.sdk.uploader.upload.parts;

import java.util.List;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;

import android.os.Build;

import edu.mtu.citizenscience.cs.sdk.json.Request;
import edu.mtu.citizenscience.cs.sdk.json.Response;
import edu.mtu.citizenscience.cs.sdk.uploader.CitsciUploaderError;
import edu.mtu.citizenscience.cs.sdk.uploader.CitsciUploaderProgress;
import edu.mtu.citizenscience.cs.sdk.uploader.CitsciUploaderService;
import edu.mtu.citizenscience.cs.sdk.uploader.model.Row;
import edu.mtu.citizenscience.cs.sdk.uploader.upload.UploadPart;
/**
 * @author Corbin Uselton <corbinu@cwuselto@mtu.edu>
 * @copyright (c) 2012 MichiganTech <http://www.mtu.edu>
 * @since 1.0
 * 
 * Uploads reports to the server
 */
public class Upload extends UploadPart {
	// the report rows to upload
	private List<Row> rows;
	// the upload id
	protected int id;
	
	/**
	 * @since 1.0
	 * 
	 * Payload for the upload start response
	 */
	public static class UploadStartResponse {
		// the id of the upload
		private int id;

		/**
		 * Get the upload id
		 * 
		 * @param   void
		 * @return	int - upload id
		 */
		public int getId() 
		{
			return id;
		}

		/**
		 * Set the upload id
		 * 
		 * @param   id - int - upload id
		 * @return	void
		 */
		public void setId(int id) 
		{
			this.id = id;
		}
	}
	
	/**
	 * @since 1.0
	 * 
	 * Upload Start request payload
	 */
	public class UploadStartRequest {
		// the device name
		private String device;

		/**
		 * Get the upload device
		 * 
		 * @param   void
		 * @return	String - device name
		 */
		public String getDevice() 
		{
			return device;
		}

		/**
		 * Set the upload device
		 * 
		 * @param   device - String - device name
		 * @return	void
		 */
		public void setDevice(String device) 
		{
			this.device = device;
		}
	}
	
	/**
	 * @since 1.0
	 * 
	 * Handles repsonse from the upload start request
	 */
	private class UploadStartResponseHandler extends UploadResponseHandler<UploadStartResponse> {

		/**
		 * Create the Upload Start Response Handler
		 * 
		 * @param   void
		 * @return	void
		 */
		public UploadStartResponseHandler() 
		{
			super(UploadStartResponse.class);
		}

		/**
		 * Called on response from the server
		 * 
		 * @param   response - Response<UploadStartResponse> - the response from the server
		 * @return	void
		 */
		@Override
		public void response(Response<UploadStartResponse> response) 
		{
			try 
			{
				// get the upload id from the response
				id = response.getPayload().getId();
				
				// upload the reports
				uploadReports();
			} 
			catch (JsonParseException e) 
			{
				e.printStackTrace();
				// pass the error parsing the response to the uploader
				uploader.sendError(CitsciUploaderError.INVALID_RESPONSE);
			} 
			catch (JsonMappingException e) 
			{
				e.printStackTrace();
				// pass the error parsing the response to the uploader
				uploader.sendError(CitsciUploaderError.INVALID_RESPONSE);
			}
			
		}
		
	}
	
	/**
	 * @since 1.0
	 * 
	 * Payload for upload complete response
	 */
	public static class UploadCompleteResponse {
		// whether the upload was successful or not
		private boolean success;

		/**
		 * Get success
		 * 
		 * @param   void
		 * @return	boolean - whether the upload was successful
		 */
		public boolean getSuccess() 
		{
			return success;
		}

		/**
		 * Set success
		 * 
		 * @param   success - boolean - whether the upload was successful
		 * @return	void
		 */
		public void setSuccess(boolean success) 
		{
			this.success = success;
		}
	}
	
	/**
	 * @since 1.0
	 * 
	 * Handles the upload complete response
	 */
	private class UploadCompleteResponseHandler extends UploadResponseHandler<UploadCompleteResponse> {
		
		/**
		 * Create the Upload Complete Response Handler
		 * 
		 * @param   void
		 * @return	void
		 */
		public UploadCompleteResponseHandler() 
		{
			super(UploadCompleteResponse.class);
		}

		/**
		 * Called on response from the server
		 * 
		 * @param   response - Response<UploadCompleteResponse> - the response from the server
		 * @return	void
		 */
		@Override
		public void response(Response<UploadCompleteResponse> response) 
		{
			try 
			{
				// check if the upload completed successfully
				if (response.getPayload().getSuccess())
				{	
					// send the progress uploaded to the uploader and the number of rows uploaded
    				uploader.sendProgress(CitsciUploaderProgress.UPLOADED, rows.size(), -1);
    				
    				// complete the upload for the rows
    				uploader.uploadComplete(rows);
				}
			} 
			catch (JsonParseException e) 
			{
				// pass the error parsing the response to the uploader
				uploader.sendError(CitsciUploaderError.INVALID_RESPONSE);
				
				e.printStackTrace();
			} 
			catch (JsonMappingException e) 
			{
				// pass the error parsing the response to the uploader
				uploader.sendError(CitsciUploaderError.INVALID_RESPONSE);
				
				e.printStackTrace();
			}
			
		}
		
	}

	/**
	 * Create the upload
	 * 
	 * @param   citsciUploaderService - CitsciUploaderService - the upload service
	 * @param	rows - List<Row> - the list of rows to upload
	 * @return	void
	 */
	public Upload(CitsciUploaderService citsciUploaderService, List<Row> rows)
	{
		super(citsciUploaderService);
		
		this.rows = rows;
	}
	
	/**
	 * Start the upload
	 * 
	 * @param   void
	 * @return	void
	 */
	public void startUpload()
	{
		// send progress starting to the uploader
		this.uploader.sendProgress(CitsciUploaderProgress.STARTING, -1, -1);
		
		// create a new start request payload
		UploadStartRequest payload = new UploadStartRequest();
		// set the device name to the manufacture name plus the product name
		payload.setDevice(Build.MANUFACTURER + ": " + Build.PRODUCT);
		
		// create a new request with the new_upload action and attach the payload
		Request<UploadStartRequest> request = new Request<UploadStartRequest>("new_upload", payload);
		
		// send the request to the server passing the upload start response handler to handle the response
		this.uploader.doRequest(request, new UploadStartResponseHandler());
	}
	
	/**
	 * Start the upload
	 * 
	 * @param   void
	 * @return	void
	 */
	public void uploadReports()
	{
		// start new reports upload with the report rows
		new Reports(uploader, this, rows).startUpload();
	}
	
	/**
	 * Complete the upload
	 * 
	 * @param   void
	 * @return	void
	 */
	public void completeUpload()
	{
		// send progress completing to the uploader
		this.uploader.sendProgress(CitsciUploaderProgress.COMPLETING, -1, -1);
		
		// create a new request with the complete_upload action and the upload id
		Request<UploadStartRequest> request = new Request<UploadStartRequest>("complete_upload", this.id);
		
		// send the request to the server passing the upload complete response handler to handle the response
		this.uploader.doRequest(request, new UploadCompleteResponseHandler());
	}
	
}
